//markers moves on page reload...

/*
(c)2006 Yegor Yarko
yaegor@gmail.com

http://yaegor.narod.ru/misc/tech/mraker.html

Uses A JavaScript implementation of the RSA Data Security by Jerrad Pierce, See http://pajhome.org.uk/crypt/md5 for more info.

Use at your own risk
*/

/*
Invocation:
preserve = true;baseUrl='http://yaegor.narod.ru/misc/tech';function loadScript(scriptURL) { var scriptElem = document.createElement('SCRIPT'); scriptElem.setAttribute('language', 'JavaScript'); scriptElem.setAttribute('src', scriptURL);document.body.appendChild(scriptElem);};document.preserveMrakers=preserve;document.mrakersBaseUrl=baseUrl;if(document.preserveMrakers){loadScript(baseUrl+'/md4.js');};loadScript(baseUrl + '/mraker.js');
*/

/*
TODO:
- use middleclick instead of doubleclick
- support Opera
- place prototype to the top right window corner
- hide Mraker on Ctrl+Esc
- drag marker to prototype to remove

*/

// relies on the defined properties:
//document.preserveMrakers = true;
//document.mrakersBaseUrl = document.URL.substring(0, document.URL.lastIndexOf("/"));

document.mraker = new Object();
document.mraker.markers = new Array();
document.mraker.count = 0;

if (document.mraker.emulateFixedUnderIE == undefined) {
    document.mraker.emulateFixedUnderIE = true;
}


function loadScript(scriptURL) {
    var scriptElem = document.createElement('SCRIPT');
    scriptElem.setAttribute('language', 'JavaScript');
    scriptElem.setAttribute('src', scriptURL);
    document.body.appendChild(scriptElem);
}

/*function addStyle(styleName, styleDef) {
    var mrakerStyleTagId = "mrakerStyles";
    var styleElem = document.getElementById(mrakerStyleTagId);
    if (styleElem == undefined) {
        styleElem = document.createElement('STYLE');
        styleElem.setAttribute('type', 'text/css');
        styleElem.id = mrakerStyleTagId;
        document.body.appendChild(styleElem);
    }
    styleElem.innerHTML = styleElem.innerHTML + "\n" +
                          "." + styleName + " {" + styleDef + "}";
}*/
if (!document.mrakersBaseUrl) {
    document.mrakersBaseUrl = "http://yaegor.narod.ru/misc/tech";
}
initialize();
if (document.preserveMrakers) {
    restoreMrakers();
    if (document.mraker.markers.length == 1) {
        positionToMarker(document.mraker.markers[0]);
    }
}

function initialize() {
    var prototypeMarkerElement = document.createElement("DIV");
    prototypeMarkerElement.id = "mrakerPrototype";

    //    addStyle("mrakerMenuStyle", "position:fixed; top:10px; left:10px; border: 1px solid blue; width:40px; height:40px; z-Index:100;");
    //    prototypeMarkerElemet.className = "mrakerMenuStyle";

    var xPosition = 10;
    var yPosition = 10;
    if (!document.all) { // FF
        prototypeMarkerElement.style.position = "fixed";
        prototypeMarkerElement.style.top = yPosition + "px";
        prototypeMarkerElement.style.right = xPosition + "px";
    } else { //IE
        prototypeMarkerElement.style.position = "absolute";
        prototypeMarkerElement.style.top = (getScrollY() + yPosition ) + "px";
        prototypeMarkerElement.style.right = xPosition + "px";
        if (document.mraker.emulateFixedUnderIE) {
            prototypeMarkerElement.intervalID = setInterval(
                    function() {
                        var elem = document.getElementById("mrakerPrototype");
                        elem.style.top = (getScrollY() + yPosition ) + "px";
                        elem.style.right = xPosition + "px";
                    }
                    , 100);
        }
    }

    prototypeMarkerElement.style.borderWidth = "1px";
    prototypeMarkerElement.style.borderStyle = "solid";
    prototypeMarkerElement.style.borderColor = "darkgray";
    prototypeMarkerElement.style.width = "40px";
    prototypeMarkerElement.style.height = "40px";
    prototypeMarkerElement.style.zIndex = "100";
    prototypeMarkerElement.style.backgroundImage = "url(" + document.mrakersBaseUrl + "/mraker_proto_bg.png)";
    prototypeMarkerElement.style.textAlign = "center";
    prototypeMarkerElement.style.verticalAlign = "middle";
    prototypeMarkerElement.title = "Drag to mark a place on a page. Click to position to the place. Doubleclick to clear markers. Alt+click to move last marker.";

    prototypeMarkerElement.onmousedown = function(locEvent) {
        log("mouseDown");
        var event = locEvent ? locEvent : window.event;
        var pageX = getEventX(event);
        var pageY = getEventY(event);
        this.downPageX = pageX;
        this.downPageY = pageY;

        document.onselectstart_stored = document.onselectstart;
        document.onselectstart_stored_active = true;
        // preventing text selection in IE
        document.onselectstart = function() {
            return false;
        };

        return false;
        // disables text selection in FF;
    };

    prototypeMarkerElement.onmouseout = function(locEvent) {
        log("mouseOut");
        if (this.downPageX) { //dragging active
            var event = locEvent ? locEvent : window.event;
            var pageX = getEventX(event);
            var pageY = getEventY(event);
            var marker = createMraker(this);
            marker.isNew = true;
            pick(marker, this.downPageX, this.downPageY);
            move(marker, pageX, pageY);
            this.downPageX = false;
            return false;
        }
        return true;
    };

    prototypeMarkerElement.onmouseup = function(locEvent) {
        //        var event = locEvent ? locEvent : window.event;
        log("mouseUp");
        this.downPageX = false;
        if (document.onselectstart_stored_active) {
            document.onselectstart = document.onselectstart_stored;
            document.onselectstart_stored_active = false;
        }
    }

    prototypeMarkerElement.onclick = function(locEvent) {
        //        var event = locEvent ? locEvent : window.event;
        log("click");
        this.downPageX = false;
        if (document.dragging != null) {
            deleteLastMarker();
        }
        if (document.mraker.markers.length == 1) {
            positionToMarker(document.mraker.markers[0]);
        } else {
            showMarkersMenu();
        }
    };
    prototypeMarkerElement.ondblclick = function(locEvent) {
        //        var event = locEvent ? locEvent : window.event;
        removeAllMarkers();
        var list = document.getElementById('mrakersList');
        if (list != undefined) {
            list.style.display = 'none';
        }
    };
    document.body.appendChild(prototypeMarkerElement);

    registerMoveOnClick();
}

function registerMoveOnClick() {
    var existingDocumentOnMouseDown = document.onmousedown;
    document.onmousedown = function(locEvent) {
        var event = locEvent ? locEvent : window.event;
        if (event.altKey) {
            var lastMarker = document.mraker.markers[document.mraker.markers.length - 1];
            if (lastMarker != null) {
                document.draggingXOffset = pixelsFromDimension(document.getElementById("mrakerPrototype").style.width)/2;
                document.draggingYOffset = pixelsFromDimension(document.getElementById("mrakerPrototype").style.height)/2;
                move(lastMarker, getEventX(event), getEventY(event));
                return false;
            }
        }
        if (typeof existingDocumentOnMouseDown == "function") {
            existingDocumentOnMouseDown();
        }	
    }
}

function getScrollX() {
    if (document.all) {
        return (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement.scrollLeft : document.body.scrollLeft;
    } else {
        return window.pageXOffset;
    }
}

function getScrollY() {
    if (document.all) {
        return (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement.scrollTop : document.body.scrollTop;
    } else {
        return window.pageYOffset;
    }
}

function getEventX(event) {
    return event.pageX ? event.pageX : event.clientX + getScrollX();
}

function getEventY(event) {
    return event.pageY ? event.pageY : event.clientY + getScrollY();
}


function deleteLastMarker() {
    var lastMarker = document.dragging;
    drop(lastMarker);
    removeMarker(lastMarker);
    document.mraker.count--;
    //            document.mraker.markers.pop();
    //            updateMarkersCount();

}

function showMarkersMenu() {
    var list = document.getElementById("mrakersList");
    if (!list) {
        list = document.createElement("DIV");
        list.id = "mrakersList";
        //                addStyle("mrakerListStyle", "position:fixed; width:30px; border: 1px solid green;");
        //                list.className = "mrakerListStyle";
        list.style.width = "30px";
        list.style.borderWidth = "1px";
        list.style.borderStyle = "solid";
        list.style.borderColor = "darkgray";
        list.style.background = "white";
        list.style.display = 'none';

        var prototypeMarker = document.getElementById("mrakerPrototype");
        if (!document.all) { //FF
            var xPosition = pixelsFromDimension(prototypeMarker.style.right);
            var yPosition = (pixelsFromDimension(prototypeMarker.style.top) +
                             pixelsFromDimension(prototypeMarker.style.height) );
            list.style.position = "fixed";
            list.style.top = yPosition + "px";
            list.style.right = xPosition + "px";
        } else {  // IE
            var xPosition = pixelsFromDimension(prototypeMarker.style.right);
            var yPosition = (pixelsFromDimension(prototypeMarker.style.top) +
                             pixelsFromDimension(prototypeMarker.style.height) ) - getScrollY();

            list.style.position = "absolute";
            list.style.right = xPosition + "px";
            list.style.top = (getScrollY() + yPosition ) + "px";
            list.style.right = xPosition + "px";
            if (document.mraker.emulateFixedUnderIE) {
                //todo: can require optimizing
                list.intervalID = setInterval(
                        function() {
                            var elem = document.getElementById("mrakersList");
                            elem.style.top = (getScrollY() + yPosition ) + "px";
                            elem.style.right = xPosition + "px";
                        }
                        , 100);
            }
        }
        document.body.appendChild(list);
    } else {
        while (list.childNodes.length > 0) {
            list.removeChild(list.childNodes[0]);
        }
    }
    for (var i = 0; i < document.mraker.markers.length; ++i) {
        var item = document.createElement("DIV");
        item.innerHTML = document.mraker.markers[i].globalIndex;
        item.style.width = "30px";
        item.style.borderWidth = "1px";
        item.style.borderStyle = "solid";
        item.style.borderColor = "darkgray";
        item.mrakerIndex = i;
        item.onclick = function(locEvent) {
            var event = locEvent ? locEvent : window.event;
            var index;
            if (event.currentTarget) {//FF
                index = event.currentTarget.mrakerIndex;
            } else {//IE
                index = event.srcElement.mrakerIndex;
            }
            positionToMarker(document.mraker.markers[index]);
            if (document.keydown_on_list_stored_active) {
                document.onkeydown = document.keydown_on_list_stored;
                document.keydown_on_list_stored_active = false;
            }
            document.getElementById("mrakersList").style.display = "none";
        }
        list.appendChild(item);
    }

    if (!document.keydown_on_list_stored_active) {
        document.keydown_on_list_stored = document.onkeydown;
        document.keydown_on_list_stored_active = true;
        document.onkeydown = function(locEvent) {
            var event = locEvent ? locEvent : window.event;
            if (event.keyCode == 27) {
                if (document.keydown_on_list_stored_active) {
                    document.onkeydown = document.keydown_on_list_stored;
                    document.keydown_on_list_stored_active = false;
                }
                document.getElementById("mrakersList").style.display = "none";
                return false;
            } else {
                return (typeof document.keydown_on_list_stored == "function") ?document.keydown_on_list_stored(event) : true;
            }
        };
    }
    if (list.childNodes.length > 0) {
        list.style.display = "block";
    }
}

function positionToMarker(marker) {
    marker.scrollIntoView();
    highlightElement(marker);
}

function createMraker(element) {
    var draggableClone = element.cloneNode(true);
    document.mraker.count++;
    draggableClone.id = "mraker" + document.mraker.count;
    draggableClone.arrayIndex = document.mraker.markers.length;
    draggableClone.globalIndex = document.mraker.count;
    draggableClone.style.zIndex = 99;
    draggableClone.style.borderColor = "#CC99CC";
    draggableClone.style.backgroundImage = "url(" + document.mrakersBaseUrl + "/mraker_bg.png)";
    draggableClone.style.position = "absolute";
    draggableClone.innerHTML = "<b>" + (document.mraker.count) + "</b>";
    draggableClone.onmousedown = function(locEvent) {
        var event = locEvent ? locEvent : window.event;
        var pageX = getEventX(event);
        var pageY = getEventY(event);
        pick(draggableClone, pageX, pageY);
        return false;
    };
    draggableClone.onmouseup = function(locEvent) {
        var event = locEvent ? locEvent : window.event;
        drop(this);
        if (document.preserveMrakers) {
            saveMrakers();
        }
    };
    draggableClone.onclick = null;

    draggableClone.ondblclick = function(locEvent) {
        var event = locEvent ? locEvent : window.event;
        removeMarker(this);
    };

    var initialPositionX;
    var initialPositionY;
    if (element.style.position == "fixed") { // used under FF
        initialPositionX = (window.scrollX + (window.innerWidth - (pixelsFromDimension(element.style.right)))) - 40 - 21 + "px";
        initialPositionY = (window.scrollY + pixelsFromDimension(element.style.top)) + "px";
    } else { //assuming position is absolute
        initialPositionX = (getScrollX() + document.body.clientWidth - pixelsFromDimension(element.style.right) - 40 - 1 ) + "px";
        initialPositionY = element.style.top;
    }
    draggableClone.style.top = initialPositionY;
    draggableClone.style.right = null;
    draggableClone.style.left = initialPositionX;
    //    alert("x,y=" + draggableClone.style.top + draggableClone.style.left);
    //


    document.mraker.markers.push(draggableClone);
    updateMarkersCount();
    document.body.appendChild(draggableClone);
    return draggableClone;
}

function updateMarkersCount() {
    document.getElementById("mrakerPrototype").innerHTML = document.mraker.markers.length;
}
function removeAllMarkers() {
    var current;
    while (document.mraker.markers.length > 0) {
        current = document.mraker.markers.pop();
        if (current != undefined && current != null) {
            document.body.removeChild(current);
        }
    }
    updateMarkersCount();
    if (document.preserveMrakers) {
        clearMrakers();
    }
}

function removeMarker(marker) {
    document.body.removeChild(marker);
    document.mraker.markers[marker.arrayIndex] = null;
    if (marker.arrayIndex == document.mraker.markers.length) {
        document.mraker.markers.pop();
    } else {
        compactMrakers();
    }
    updateMarkersCount();
    if (document.preserveMrakers) {
        saveMrakers();
    }
}

function compactMrakers() {
    var storingIndex = 0
    for (var listingIndex = 0; listingIndex < document.mraker.markers.length; ++listingIndex) {
        if (document.mraker.markers[listingIndex] == null) {
        } else {
            document.mraker.markers[storingIndex] = document.mraker.markers[listingIndex];
            document.mraker.markers[storingIndex].arrayIndex = storingIndex;
            storingIndex++;
        }
    }
    document.mraker.markers.length = storingIndex;
}

// element is assumed to have absolute positioning
function pick(element, downPageX, downPageY) {
    var currentX = pixelsFromDimension(element.style.left);
    var currentY = pixelsFromDimension(element.style.top);

    document.dragging = element;
    document.draggingXOffset = downPageX ? downPageX - currentX : 0;
    document.draggingYOffset = downPageY ? downPageY - currentY : 0;
    document.onmousemove_stored = document.onmousemove;
    document.onmousemove = function(locEvent) {
        if (document.dragging) {
            var event = locEvent ? locEvent : window.event;
            var moveToX = getEventX(event);
            var moveToY = getEventY(event);
            move(document.dragging, moveToX, moveToY);
            return false;
        }
        return true;
    };

    if (!document.keydown_on_move_stored_active) {
        document.keydown_on_move_stored = document.onkeydown;
        document.keydown_on_move_stored_active = true;
        document.onkeydown = function(locEvent) {
            var event = locEvent ? locEvent : window.event;
            if (document.dragging && event.keyCode == 27) {
                if (element.isNew) {
                    deleteLastMarker();
                    document.onkeydown = document.keydown_on_move_stored;
                    document.keydown_on_move_stored_active = false;
                } else {
                    move(element, currentX + document.draggingXOffset, currentY + document.draggingYOffset);
                    drop(element);
                }
                return false;
            } else {
                return (typeof document.keydown_on_move_stored == "function") ?document.keydown_on_move_stored(event) : true;
            }
        };
    }
    document.elementProperties_stored = new Object();
    document.elementProperties_stored.position = element.style.position;
    element.style.position = "absolute";
}

function pixelsFromDimension(dimension) {
    return parseInt(dimension.replace(/px/, ""));
}

function ifExist(value) {
    if (value) {
        return value;
    }
    return 0;
}

function move(element, moveToPageX, moveToPageY) {
    log(moveToPageX, "moveToPageX");
    log(moveToPageY, "moveToPageY");
    var xPosition = moveToPageX - (document.draggingXOffset ? document.draggingXOffset : 0);
    var yPosition = moveToPageY - (document.draggingYOffset ? document.draggingYOffset : 0);
    element.style.left = xPosition + "px";
    element.style.top = yPosition + "px";
}

function drop(element) {
    document.dragging = null;
    document.onmousemove = document.onmousemove_stored;
    if (document.keydown_on_move_stored_active) {
        document.onkeydown = document.keydown_on_move_stored;
        document.keydown_on_move_stored_active = false;
    }
    if (document.onselectstart_stored_active) {
        document.onselectstart = document.onselectstart_stored;
        document.onselectstart_stored_active = false;
    }
    element.isNew = false;
}

function log(value, variable) {
    var logElement = document.getElementById("log");
    if (logElement != undefined) {
        var message = (variable != null ? "<b>" + variable + "</b>: " : "") + value;
        logElement.innerHTML = message + "<br/>" + logElement.innerHTML;
    }
}

function saveMrakers() {
    var data = "";
    for (var i = 0; i < document.mraker.markers.length; i++) {
        var item = document.mraker.markers[i];
        data = data + i + ":" + pixelsFromDimension(item.style.left) + ":" + pixelsFromDimension(item.style.top) + ";";
    }
    saveString("mrakers" + getPageID(), data);
    //    saveString("mrakers" + getPageID(), data, getDocumentFullName());
    //todo: find a way to use path...
}

function restoreMrakers() {
    var value = getString("mrakers" + getPageID());
    //alert("Retrieved data: " + value + " for page ID: " + getPageID());
    if (value == null) {
        return;
    }
    var markersData = value.split(";");
    for (var i = 0; i < markersData.length; i++) {
        var data = markersData[i];
        if (data == "") {
            continue;
        }
        var markerData = data.split(":");
        var index = markerData[0];
        var pageX = markerData[1];
        var pageY = markerData[2];
        var marker = createMraker(document.getElementById("mrakerPrototype"));
        pick(marker);
        move(marker, pageX, pageY);
        drop(marker);
    }
}

function clearMrakers() {
    clearString("mrakers" + getPageID());
}

function highlightElement(elem) {
    var color_stored = elem.style.borderColor;
    var colorShift = 0;
    var i = 0;
    var intervalId = setInterval(function() {
        //"rgb(204,153,204)"; //#CC99CC
        elem.style.borderColor = "rgb(" + (204 - colorShift) + "," + (153 - colorShift) + "," + (204 - colorShift) + ")";
        ++i;
        colorShift = (i * 10) % 256;
        if (i > 100) {
            clearInterval(intervalId);
            elem.style.borderColor = color_stored;
        }
    }, 1)
}

//   REMEMBERING DATA VIA COOKIES

function getDocumentFullName() {
    var noProtocolUrl = document.URL.substring(document.URL.indexOf("//") + 2);
    var parametersStartIndex = noProtocolUrl.indexOf("?");
    if (parametersStartIndex == -1) {
        return noProtocolUrl;
    } else {
        return noProtocolUrl.substring(0, parametersStartIndex);
    }
}
function getPageID() {
    var endOfLocation = document.URL.indexOf("#");
    if (endOfLocation == -1) {
        endOfLocation = document.URL.length;
    }
    var pageID = "";
    if (window.hex_md4) {
        pageID = hex_md4(document.URL.substring(0, endOfLocation));
    }

    return pageID;
    //    return pageID.substr(0, 4);
}

function saveString(name, data, path) {
    var exp = new Date()
    var oneYearFromNow = exp.getTime() + (365 * 24 * 60 * 60 * 1000)
    exp.setTime(oneYearFromNow)
    document.cookie = name + "=" + escape(data) + ";"
            + "expires=" + exp.toGMTString() + ";"
            + (path ? "path=" + path + ";" : "")
            ;
}

function getString(name) {
    var cookies = document.cookie;
    var startNameIndex = cookies.indexOf(name);
    if (startNameIndex == -1) {
        return null;
    }
    var startValueIndex = cookies.indexOf(name) + (name + "=").length;
    var endValueIndex = cookies.indexOf(";", startValueIndex-1);
    if (endValueIndex == -1) {
        endValueIndex = cookies.length;
    }else if(endValueIndex == -1){
        return null;
    }
    var value = cookies.substring(startValueIndex, endValueIndex);
    return unescape(value);
}

function clearString(name, path) {
    if (getString(name) != null) {
        document.cookie = name + "="
                + (path ? "path=" + path + ";" : "")
                + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}


